﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Chenglin.WPChildrenDrug.Models
{
    public class DrugData
    {
        private Drug[] _data;
        private TrieTree _tree;
        private Dictionary<string, int> _map;

        /// <summary>
        /// Get all the data.
        /// </summary>
        public Drug[] Data
        {
            get { return _data; }
        }

        public DrugData(Drug[] data)
        {
            if (data == null)
            {
                throw new ArgumentException("data");
            }

            // Sort the data with its name (case insensitive)
            //
            _data = data;
            Array.Sort(_data, (x, y) => string.Compare(x.Name, y.Name, StringComparison.OrdinalIgnoreCase));

            // Init the dictionary and the trie tree
            //
            _tree = new TrieTree();
            _map = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
            for (int drugIndex = 0; drugIndex < _data.Length; drugIndex++)
            {
                string name = _data[drugIndex].Name;
                _map.Add(name, drugIndex);

                // We'll index every character in the names.
                int pos = 0;
                while (pos < name.Length)
                {
                    string subStr = (pos == 0) ? name : name.Substring(pos);

                    TrieNode node = _tree.Insert(subStr);
                    _tree.AddIndex(node, drugIndex);

                    // move to the next character
                    pos++;
                }
            }
        }

        public Drug GetDrug(string name)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }

            int idx;
            if (_map.TryGetValue(name, out idx))
            {
                return _data[idx];
            }

            // Not found
            return null;
        }

        /// <summary>
        /// Search all the drug data on its name.
        /// TODO: we can return exact match results as the first one.
        /// </summary>
        public Drug[] Search(string s)
        {
            if (string.IsNullOrEmpty(s))
            {
                return new Drug[0];
            }

            // Search the trie tree
            TrieNode node = _tree.Find(s);
            if (node == null || node.Indexes.Count == 0)
            {
                return new Drug[0];
            }

            // Build the result list
            return (from idx in node.Indexes select _data[idx]).ToArray();
        }
    }
}
